#ifndef LISTA_H
#define LISTA_H

#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>

/* *****************************************************************
 *                DEFINICION DE LOS TIPOS DE DATOS				   *
 * *****************************************************************/

/* Se trata de una lista con iterador que contiene datos de tipo void* 
 * (punteros genéricos).  La lista en sí está definida en el .c.  */

typedef struct lista lista_t;
typedef struct iterador lista_iter_t;


/* *****************************************************************
 *                      PRIMITIVAS DE LA LISTA                 	   *
 * *****************************************************************/

// Crea una lista.
// Post: devuelve una nueva lista vacía.
lista_t* lista_crear();

// Devuelve verdadero o falso, según si la lista tiene o no elementos enlazados.
// Pre: la lista fue creada.
bool lista_esta_vacia (const lista_t *lista);

// Destruye la lista. Si se recibe la función destruir_dato por parámetro,
// para cada uno de los elementos de la lista llama a destruir_dato.
// Pre: la lista fue creada. 'destruir_dato' es una función capaz de destruir
// los datos de la cola, o NULL en caso de que no se la utilice.
// Post: se eliminaron todos los elementos de la lista.
void lista_destruir (lista_t *lista, void destruir_dato(void *));

// Agrega un nuevo elemento a la lista. Devuelve falso en caso de error.
// Pre: la lista fue creada.
// Post: se agregó un nuevo elemento al principio o al final de la lista
// según corresponda, 'dato' es dicho elemento.
bool lista_insertar_primero (lista_t *lista,void *dato);
bool lista_insertar_ultimo (lista_t *lista,void *dato);

// Obtiene el valor del primer elemento de la lista. Si la lista tiene elementos,
// se devuelve el valor del primer elemento. Si está vacía devuelve NULL.
// Pre: la lista fue creada.
// Post: se devolvió el valor del primer elemento de la lista sin sacarlo
// de ella, cuando ésta no está vacía; NULL en caso contrario.
void* lista_ver_primero (const lista_t *lista);

// Saca el primer elemento de la lista. Si la lista tiene elementos,
// se quita el primero de la lista, y se devuelve ese valor. Si la lista
// está vacía, devuelve NULL.
// Pre: la lista fue creada.
// Post: si la lista no estaba vacía, se devuelve el primer valor de ella
// y la lista contiene un elemento menos.
void* lista_borrar_primero(lista_t *lista);

// Devuelve el largo de la lista.
// Pre: la lista fue creada.
// Post: se devolvió el largo de la lista. En caso de estar vacía,
// lógicamente, la función devuelve 0 (cero).
size_t lista_largo (const lista_t *lista);


/* *****************************************************************
 *                    PRIMITIVAS DEL ITERADOR                      *
 * *****************************************************************/
 
// Crea un iterador.
// Pre: la lista fue creada.
// Post: se creó un iterador que apunta hacia la primer posición de la lista.
lista_iter_t* lista_iter_crear(const lista_t *lista);

// El iterador avanza en una posición de la lista. Si la lista no tiene
// elementos o el iterador se encuentra al final de ella, devuelve falso.
// Pre: la lista y el iterador fueron creados.
// Post: el iterador avanzó a la posición siguiente de ser posible.
bool lista_iter_avanzar(lista_iter_t *iter);

// Da el valor de la posición donde se encuentra el iterador. Si dicha
// posición está vacía, devuelve NULL.
// Pre: la lista y el iterador fueron creados.
// Post: se devolvió el valor de la posición donde se encuentra el iterador
// o NULL, según corresponda.
void* lista_iter_ver_actual(const lista_iter_t *iter);

// Devuelve verdadero si el iterador se encuentra al final de la lista,
// falso en caso contrario.
// Pre: la lista y el iterador fueron creados.
bool lista_iter_al_final(const lista_iter_t *iter);

// Destruye el iterador.
// Pre: el iterador fue creado.
// Post: se destruyó el iterador.
void lista_iter_destruir(lista_iter_t *iter);


/* *****************************************************************
 *              PRIMITIVAS DE LA LISTA Y EL ITERADOR               *
 * *****************************************************************/

// Se agrega 'dato' a la lista en la posición en la que se encuentra el
// iterador. Devuelve falso en caso de error.
// Pre: la lista y el iterador fueron creados.
// Post: se insertó 'dato' a la lista de ser posible.
bool lista_insertar(lista_t *lista, lista_iter_t *iter, void *dato);

// Saca de la lista el elemento que corresponda con la posición en la
// que se encuentre el iterador y lo devuelve. Devuelve NULL si la posición
// no contiene elemento alguno.
// Pre: la lista y el iterador fueron creados.
// Post: se devolvió el elemento o NULL según corresponda.
void* lista_borrar(lista_t *lista, lista_iter_t *iter);

#endif // LISTA_H
